﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Threading;
using System.Windows.Forms;
using __ts.Core.Configuration;
using __ts.Core.Log;
using __ts.Core.Utilities;

namespace CCU.Update
{
    public partial class UrlDownloader : Form
    {
        /// <summary>
        /// 
        /// </summary>
        public bool downloadOk { get; set; }
        /// <summary>
        /// 更新包
        /// </summary>
        public Dictionary<string, DownloadPackageInfo> pks;
        /// <summary>
        /// 
        /// </summary>
        private bool autoRun = false;
        /// <summary>
        /// 
        /// </summary>
        private string flowId;
        /// <summary>
        /// 
        /// </summary>
        private ManualResetEvent[] m_ResetEvents;
        /// <summary>
        /// 本地保存路径
        /// </summary>
        private string localDir;
        /// <summary>
        /// 
        /// </summary>
        private bool hasFailed;

        public UrlDownloader(string flowId, bool autoRun, Dictionary<string, DownloadPackageInfo> packs)
        {
            if (packs == null || packs.Count < 1)
                return;

            this.flowId = flowId;
            this.autoRun = autoRun;

            Form.CheckForIllegalCrossThreadCalls = false;
            InitializeComponent();
            this.pks = packs;
            this.downloadOk = false;
            this.localDir = Util.RootPath + string.Format("\\update\\{0}\\{1}", DateTime.Now.ToString("yyyyMMdd"), this.flowId);
            this.backgroundWorker1.RunWorkerAsync();
        }

        /// <summary>
        /// 显示提示内容
        /// </summary>
        /// <param name="str"></param>
        private void ShowTip(String str)
        {
            this.lbUpdate.Items.Add(str);
            this.lbUpdate.SelectedIndex = this.lbUpdate.Items.Count - 1;
        }
        /// <summary>
        /// 检查文件是否存在
        /// </summary>
        /// <param name="fileUrl"></param>
        /// <param name="timeOut"></param>
        /// <returns></returns>
        private bool FileExists(string fileUrl, int timeOut)
        {
            bool result = false;
            HttpWebResponse response = null;
            try
            {
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(fileUrl);
                request.Timeout = 1000 * timeOut;
                request.ReadWriteTimeout = 1000 * timeOut;
                response = (HttpWebResponse)request.GetResponse();
                result = response == null ? false : true;
            }
            catch (Exception)
            {
                result = false;
            }
            finally
            {
                if (response != null)
                {
                    response.Close();
                }
            }
            return result;
        }
        /// <summary>
        /// 下载完成事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void web_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            string id = e.UserState.ToString();
            DownloadPackageInfo p = pks[id];
            string savePath = string.Format("{0}\\{1}", localDir, id + ".7rd");

            ShowTip(string.Format("{0}:[{1}] {2}.",
                        DateTime.Now.ToString("yyyy/MM/dd HH:mm"),
                        p.id,
                        "download successful"
                        ));

            //获得文件md5
            string md5Code = Util.GetMd5(savePath).ToLower();
            if (md5Code == null)
            {
                ShowTip(string.Format("{0}:[{1}] {2}.",
                        DateTime.Now.ToString("yyyy/MM/dd HH:mm"),
                        p.id,
                        "get package md5 code error"
                        ));
            }

            //对比文件md5
            if (!md5Code.Equals(p.md5))
            {
                ShowTip(string.Format("{0}:[{1}] {2}.",
                        DateTime.Now.ToString("yyyy/MM/dd HH:mm"),
                        p.id,
                        "package md5 error"
                        ));
                p.state = 2;
                File.Delete(p.savePath);
            }
            else
            {
                ShowTip(string.Format("{0}:[{1}] {2}.",
                        DateTime.Now.ToString("yyyy/MM/dd HH:mm"),
                        p.id,
                        "checked ok"
                        ));
                p.state = 3;
                this.progressBar_down.Value += (100 / this.pks.Count);
            }
            m_ResetEvents[p.index].Set();
        }
        /// <summary>
        /// 下载文件
        /// </summary>
        private void DownLoad()
        {
            IDictionaryEnumerator enumerator = this.pks.GetEnumerator();
            m_ResetEvents = new ManualResetEvent[this.pks.Count];
            int i = 0;
            while (enumerator.MoveNext())
            {
                DownloadPackageInfo p = enumerator.Value as DownloadPackageInfo;
                p.index = i;
                m_ResetEvents[i] = new ManualResetEvent(false);
                if (p.state == 3)
                {
                    m_ResetEvents[i].Set();
                    i++;
                    continue;
                }
                else if (p.state == 0)
                {
                    p.fileUrl = string.Format("{0}/Update/Jv6az3A_Dfh3-aO5eqc/{1}/{2}",
                        ConfigManager.GlobalAppSettings["PackageStore"],
                        Convert.ToDateTime(p.publishTime).ToString("yyyyMMdd"),
                        p.id + ".7rd");

                    p.savePath = string.Format("{0}\\{1}", localDir, p.id + ".7rd");
                }

                if (FileExists(p.fileUrl, 20))
                {
                    WebClient web = new WebClient();
                    web.DownloadFileCompleted += new AsyncCompletedEventHandler(web_DownloadFileCompleted);

                    ShowTip(string.Format("{0}:[{1}] {2}.",
                        DateTime.Now.ToString("yyyy/MM/dd HH:mm"),
                        p.id,
                        "connect successful, downloading..."
                        ));

                    if (!Directory.Exists(localDir))
                        Directory.CreateDirectory(localDir);

                    if (File.Exists(p.savePath))
                    {
                        if (Util.GetMd5(p.savePath).ToLower() == p.md5)
                            return;
                        else
                            File.Delete(p.savePath);
                    }

                    //执行下载
                    p.state = 1;
                    web.DownloadFileAsync(new Uri(p.fileUrl), p.savePath, p.id);
                    web.Dispose();
                }
                else
                {
                    ShowTip(string.Format("{0}:[{1}] {2}.",
                        DateTime.Now.ToString("yyyy/MM/dd HH:mm"),
                        p.id,
                        "connect failed."
                        ));

                    p.state = 2;
                    m_ResetEvents[i].Set();
                }
                i++;
            }
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            this.hasFailed = false;
            do
            {
                if (flag) break;

                this.DownLoad();
                WaitHandle.WaitAll(m_ResetEvents);
                ShowTip(" ====== failed ======");
                IDictionaryEnumerator enumerator = this.pks.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    DownloadPackageInfo p = enumerator.Value as DownloadPackageInfo;
                    if (p.state != 3)
                    {
                        hasFailed = true;
                        ShowTip(string.Format(" => {0}", p.id));
                    }
                }
                if (hasFailed)
                {
                    ShowTip(" download again in 10s.");
                    Thread.Sleep(1000 * 10);
                }
                else
                {
                    ShowTip(" none");
                    downloadOk = true;
                    WriteLog();
                    this.Close();
                }
                ShowTip(" ");
            } while (hasFailed);
        }
        private bool flag = false;
        private void btnInstall_Click(object sender, EventArgs e)
        {
            flag = true;
            downloadOk = true;
            btnInstall.Enabled = false;
            backgroundWorker1.CancelAsync();
            WriteLog();
            this.Close();
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            
        }

        public void WriteLog()
        {
            for (int i = 0; i < this.lbUpdate.Items.Count; i++)
            {
                Logger.Write(this.lbUpdate.Items[i].ToString());
            }
        }
    }
}
